using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Items;
using Server.Mobiles;
using Server.Gumps;
using Server.Targeting;
using Server.Network;
using Server.Multis;
using Server.ContextMenus;
using Server.Regions;
using Server.Misc;
using Server.Spells;


namespace Server.Mobiles
{
	public class PetSeller : WanderingTrader
	{
		private ArrayList m_SBInfos = new ArrayList();
		protected override ArrayList SBInfos{ get { return m_SBInfos; } }

		public static readonly double ShowDelay = 5.0;

		private bool m_InitPet;
		private bool m_OnShow;
		private DateTime m_NextShow;

		[CommandProperty( AccessLevel.GameMaster)]
		public bool OnShow
		{
			get{ return m_OnShow; }
			set{ m_OnShow = value; InvalidateProperties(); }
		}

		[CommandProperty( AccessLevel.GameMaster)]
		public DateTime NextShow
		{
			get{ return m_NextShow; }
			set{ m_NextShow = value; InvalidateProperties(); }
		}


		[Constructable]
		public PetSeller( Mobile owner, VendorManager vm ) : this( owner, vm, "the Pet Seller" )
		{
		}

		[Constructable]
		public PetSeller( Mobile owner, VendorManager vm, string title ) : base( owner, vm, title )
		{
			ShopItems = new Hashtable();
			Currency = typeof( Gold );

			m_InitPet = false;

			AllowBid = true;
			m_OnShow = false;
			m_NextShow = DateTime.Now + TimeSpan.FromSeconds( 30.0 );

			IsComm = true;
			Owner = owner;
			Manager = vm;
		}

		public PetSeller( Serial serial ) : base( serial )
		{
		}

		public override void InitSBInfo()
		{
		}


		public static void ToHidePets( Mobile master )
		{
			List<Mobile> move = new List<Mobile>();

			foreach ( Mobile m in master.GetMobilesInRange( 3 ) )
			{
				if ( m is BaseCreature )
				{
					BaseCreature pet = (BaseCreature)m;

					if ( pet.Controlled && pet.ControlMaster == master )
						move.Add( pet );
				}
			}

			foreach ( Mobile m in move )
			{
				BaseCreature bc = (BaseCreature)m;

				bc.ControlTarget = null;
				bc.ControlOrder = OrderType.Stay;
				bc.Internalize();

				bc.SetControlMaster( null );
				bc.SummonMaster = null;

				bc.IsStabled = true;
				bc.Loyalty = BaseCreature.MaxLoyalty;	// Wonderfully happy
				bc.Blessed = false;
			}
		}

		public bool IsQualified( BaseCreature bc )
		{
			return ( bc.IsBonded && bc.HitsMax > 450 );
		}

		public override void OnThink()
		{
			base.OnThink();

			if ( ShopItems == null || !( ShopItems.Count > 0 ) )
				return;

			if ( Manager == null || Manager.Deleted )
				return;

			if ( m_InitPet )
			{
				ToHidePets( (Mobile)this );
				m_InitPet = false;
			}

			if ( Manager.ShowTime > DateTime.Now )
				return;

			Manager.ShowTime += Manager.ShowDelay;

			if ( !m_OnShow && ShopItems != null )
			{
				foreach ( TradeItem ti in ShopItems.Values )
				{
					BaseCreature bc = ((CloneMobile)ti.ItemObj).ClonePet as BaseCreature;

					if ( bc != null && bc.ControlMaster != null && bc.ControlMaster == (Mobile)this )
					{
						RoadShow rs = new RoadShow( (Mobile)this, (Mobile)bc, 1.0 );

						rs.HidePet();
					}
				}
			}

//			Console.WriteLine( "Show: {0}.", DateTime.Now.ToString() );		// debug code

			if ( DateTime.Now > m_NextShow && !m_OnShow )
			{
				this.PublicOverheadMessage( MessageType.Yell, 0, false, "Show time is going to start..." );
				BeginShowTime();
			}
		}

		private void BeginShowTime()
		{
			bool found = false;
			double duration = Manager.ShowSpan / 2;

			foreach ( Mobile m in this.GetMobilesInRange( 16 ) )
			{
				if ( m is PlayerMobile && !m.Hidden )
				{
					Manager.ShowTime += TimeSpan.FromMinutes( Manager.ShowSpan );
					m_NextShow = DateTime.Now + TimeSpan.FromMinutes( ShowDelay );
					found = true;
				}
			}

//			Console.WriteLine( "Found Mobile: {0}", found.ToString() );		// debug code

			if ( !found )
			{
				this.PublicOverheadMessage( MessageType.Yell, 0, false, "No customer yet..." );
				return;
			}

			List<Mobile> list = new List<Mobile>();
			Mobile mob = null;

			foreach ( TradeItem ti in ShopItems.Values )
			{
				Item item = (Item)ti.ItemObj;

				if ( item is CloneMobile )
					mob = ((CloneMobile)item).ClonePet as Mobile;

				if ( mob != null )
					list.Add( mob );
			}

			if ( list == null || !( list.Count > 0 ) )
				return;

			int pick = Utility.Random( list.Count );
			Mobile pet = list[pick];

			RoadShow rs = new RoadShow( (Mobile)this, pet, duration );

			rs.m_timer = 
				Timer.DelayCall( TimeSpan.FromSeconds( 10.0 ), TimeSpan.FromSeconds( 10.0 ), new TimerStateCallback( ProcessRoadShow ), rs );
		}

		private static void ProcessRoadShow( object state )
		{
			RoadShow rs = (RoadShow) state;

			Mobile vendor = rs.m_from;
			BaseCreature pet = rs.m_pet as BaseCreature;
			IHardsellable hs = vendor as IHardsellable;

			if ( !rs.m_shown || DateTime.Now >= rs.m_endtime || vendor.Deleted || hs.Manager == null 
				|| hs.Manager.Deleted || vendor.Map != pet.Map || pet.ControlMaster != vendor )
			{
				if ( rs.m_timer != null )
					rs.m_timer.Stop();

//				Console.WriteLine( "Show Stop: {0}", DateTime.Now.ToString() );		// debug code
				vendor.PublicOverheadMessage( MessageType.Yell, 0, false, "Show finished." );

				if ( pet.ControlMaster == vendor ) 
					rs.HidePet();

				PetSeller ps = vendor as PetSeller;

				if ( ps != null && !ps.Deleted )
					ps.OnShow = false;
			}
			else
			{
				rs.SpeakRandomSpeech( vendor );
				rs.PlayRandomEffect( vendor, pet );
				rs.PlayRandomSound( vendor, pet );
			}
		}

		private class RoadShow
		{
			public Mobile m_from;
			public Mobile m_pet;
			public DateTime m_endtime;
			public Timer m_timer;
			public bool m_shown;

			public RoadShow( Mobile from, Mobile pet, double duration )
			{
				m_from = from;
				m_pet = pet;

				m_endtime = DateTime.Now + TimeSpan.FromMinutes( duration );
				m_shown = false;

				ShowPet();
				if ( m_shown && m_pet != null && !m_pet.Deleted && ((BaseCreature)m_pet).ControlMaster != null 
					&& ((BaseCreature)m_pet).ControlMaster is PetSeller )
				{
					PetSeller ps = ((BaseCreature)m_pet).ControlMaster as PetSeller;

					if ( ps != null && !ps.Deleted )
						ps.OnShow = true;
				}
			}

			public void ShowPet()
			{
				if ( m_pet == null || m_pet.Deleted )
					return;

				if ( m_from.Followers + ((BaseCreature)m_pet).ControlSlots > m_from.FollowersMax )
					return;

				Point3D p = new Point3D( m_from );

				if( SpellHelper.FindValidSpawnLocation( m_from.Map, ref p, true ) )
				{
					BaseCreature bc = m_pet as BaseCreature;
					m_shown = true;

					bc.SetControlMaster( m_from );
					bc.ControlTarget = m_from;
					bc.ControlOrder = OrderType.Follow;
					
					bc.Blessed = true;
					bc.MoveToWorld( p, m_from.Map );

					bc.IsStabled = false;
					Effects.PlaySound( p, bc.Map, 0x217 );
				}
			}

			public void HidePet()
			{
				if ( m_pet == null || m_pet.Deleted )
					return;

				BaseCreature bc = m_pet as BaseCreature;

				bc.ControlTarget = null;
				bc.ControlOrder = OrderType.Stay;
				bc.Internalize();

				bc.SetControlMaster( null );
				bc.SummonMaster = null;

				bc.IsStabled = true;
				bc.Loyalty = BaseCreature.MaxLoyalty;	// Wonderfully happy
				bc.Blessed = false;

				Effects.SendLocationParticles( EffectItem.Create( bc.Location, bc.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 );
				m_shown = false;
			}

			public void PlayRandomEffect( Mobile from, Mobile pet )
			{
				Mobile src = from;
				Mobile dest = pet;

				if ( Utility.RandomBool() )
				{
					src = pet;
					dest = from;
				}

				switch ( Utility.Random( 6 ) )
				{
					case 0:
					{
						src.PlaySound( 0x212 );
						src.PlaySound( 0x206 );

						Effects.SendLocationParticles( EffectItem.Create( src.Location, src.Map, EffectItem.DefaultDuration ), 0x376A, 1, 29, 0x47D, 2, 9962, 0 );
						Effects.SendLocationParticles( EffectItem.Create( new Point3D( src.X, src.Y, src.Z - 7 ), src.Map, EffectItem.DefaultDuration ), 0x37C4, 1, 29, 0x47D, 2, 9502, 0 );

						break;
					}
					case 1:
					{
						src.PlaySound( 0x45 );
						dest.FixedEffect( 0x376A, 1, 32 );

						break;
					}
					case 2:
					{
						Effects.PlaySound( src.Location, src.Map, 0x1FB );
						Effects.PlaySound( src.Location, src.Map, 0x10B );
						Effects.SendLocationParticles( EffectItem.Create( src.Location, src.Map, EffectItem.DefaultDuration ), 0x37CC, 1, 40, 97, 3, 9917, 0 );
						dest.FixedParticles( 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255 );

						break;
					}
					case 3:
					{
						src.PlaySound( 0x20F );
						src.PlaySound( src.Body.IsFemale ? 0x338 : 0x44A );
						src.FixedParticles( 0x376A, 1, 31, 9961, 1160, 0, EffectLayer.Waist );
						src.FixedParticles( 0x37C4, 1, 31, 9502, 43, 2, EffectLayer.Waist );

						break;
					}
					case 4:
					{
						src.PlaySound( 0x20C );
						src.PlaySound( 0x56 );
						src.FixedParticles( 0x3779, 1, 30, 9964, 3, 3, EffectLayer.Waist );
						Effects.SendMovingParticles( src, dest, 0xF5F, 1, 0, false, false, 33, 3, 9501, 1, 0, EffectLayer.Head, 0x100 );

						break;
					}
					case 5:
					{
						from.PlaySound( 0x15F );
						Effects.SendPacket( from, from.Map, new HuedEffect( EffectType.Moving, from.Serial, Serial.Zero, 0x36D4, from.Location, pet.Location, 5, 0, false, true, 0, 0 ) );

						break;
					}
				}
			}

			public void SpeakRandomSpeech( Mobile from )
			{
				switch ( Utility.Random( 6 ) )
				{
					case 0:	from.PublicOverheadMessage( MessageType.Yell, 1159, false, "This is the stongest pet in this world..." ); break;
					case 1: from.PublicOverheadMessage( MessageType.Yell, 1159, false, "You can never find another pet as good as this..." ); break;
					case 2: from.PublicOverheadMessage( MessageType.Yell, 1159, false, "This pet is so wonderful to be with..." ); break;
					case 3: from.PublicOverheadMessage( MessageType.Yell, 1159, false, "This pet is not expensive at all, and it may some day save your life..." ); break;
					case 4: from.PublicOverheadMessage( MessageType.Yell, 1159, false, "This pet is truly brave and skillful, and it's beautiful too..." ); break;
					case 5: from.PublicOverheadMessage( MessageType.Yell, 1159, false, "This pet is always loyal to its master..." ); break;
				}

				from.LocalOverheadMessage( MessageType.Emote, 0x59, 1010597 ); // You start to tame the creature.
				from.NonlocalOverheadMessage( MessageType.Emote, 0x59, 1010598 ); // *begins taming a creature.*

				switch ( Utility.Random( 3 ) )
				{
					case 0: from.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 502790, 4 ) ); break;
					case 1: from.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 1005608, 6 ) ); break;
					case 2: from.PublicOverheadMessage( MessageType.Regular, 0x3B2, Utility.Random( 1010593, 4 ) ); break;
				}
			}

			public void PlayRandomSound( Mobile vendor, Mobile pet )
			{
				Mobile mob = null;

				if ( Utility.RandomBool() )
					mob = pet;
				else
					mob = vendor;

				switch ( Utility.Random( 5 ) )
				{
					case 0: mob.PlaySound( mob.GetAngerSound() ); break;
					case 1: mob.PlaySound( mob.GetIdleSound() ); break;
					case 2: mob.PlaySound( mob.GetAttackSound() ); break;
					case 3: mob.PlaySound( mob.GetHurtSound() ); break;
					case 4: mob.PlaySound( mob.GetDeathSound() ); break;
				}
			}
		}

		public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
		{
			if ( from.Alive && !Deleted && from.AccessLevel < AccessLevel.GameMaster )
				list.Add( new HirePetSellerEntry( from, this ) );

			base.GetContextMenuEntries( from, list );
		}

		public override void Serialize( GenericWriter writer )
		{
			base.Serialize( writer );

			writer.Write( (int) 0 ); // version
		}

		public override void Deserialize( GenericReader reader )
		{
			base.Deserialize( reader );
			int version = reader.ReadInt();

			m_InitPet = true;
			m_OnShow = false;
			m_NextShow = DateTime.Now + TimeSpan.FromMinutes( ShowDelay );
		}

		private class HirePetSellerEntry : ContextMenuEntry
		{
			private Mobile m_Mobile;
			private Mobile m_Vendor;

			public HirePetSellerEntry( Mobile from, Mobile vendor ) : base( 6120, 3 )
			{
				m_Mobile = from;
				m_Vendor = vendor;

				Enabled = ( m_Mobile.Alive && m_Vendor is PetSeller );
			}

			public override void OnClick()
			{
				VendorManager.AddHardItem( m_Mobile, m_Vendor );
			}
		}
	}
}